#include "docview.h"
#include <iostream>
//#include <libgnomeuimm.h>
//#include <libgnomevfsmm.h>
#include "inputtextdialog.h"
#include "calendardialog.h"
DocView::DocView()
    :mydoc(0),removewritingMenu("Remove Writing"),removetagMenu("Remove Tag"),editdocMenu("Rename"),
     removereadingMenu("Remove Reading"),addreadingMenu("Insert into reading..."),
     addthumbMenu("Set thumbnail..."),attachMenu("Open attachment")
{
    //Create the Tree model:
    refListModel = Gtk::ListStore::create(columns);
    nullList=Gtk::ListStore::create(columns);
    set_model(refListModel);
    set_selection_mode(Gtk::SELECTION_MULTIPLE);
    //简单实现显示功能
    set_text_column(columns.name);
    //带编辑功能?
    //doccolumn.pack_start(cellrenderer);
    //set_markup_column(doccolumn);
    set_pixbuf_column(columns.pixbuf);
    set_item_width(150);
    set_row_spacing(10);
    set_margin(5);
    set_spacing(15);
    set_reorderable();
    set_double_buffered();
    //set_columns(-1);
    signal_item_activated().connect(sigc::mem_fun(*this,&DocView::select_doc));
    //doccolumn.set_cell_data_func(cellrenderer, sigc::mem_fun(*this, &DocView::datarender) );
    //cellrenderer->signal_edited().connect(sigc::mem_fun(*this, &DocView::save_doc) );
    std::vector<Gtk::TargetEntry> targets;
    targets.push_back( Gtk::TargetEntry("DOCUMENT-ID") );
    drag_source_set(targets);
    enable_model_drag_source(targets);
    signal_drag_data_get().connect(sigc::mem_fun(*this,&DocView::drag_data_get));
    //enable_model_drag_dest();
    //Fill popup menu:
    {
        Gtk::Menu::MenuList& menulist = menuPopup.items();
        //editdocMenu.signal_activate().connect(sigc::mem_fun(*this, &DocView::edit_doc));
        addthumbMenu.signal_activate().connect(sigc::mem_fun(*this,&DocView::add_thumb));
        removereadingMenu.signal_activate().connect(sigc::mem_fun(*this,&DocView::remove_reading));
        addreadingMenu.signal_activate().connect(sigc::mem_fun(*this,&DocView::add_reading));
        //menulist.push_back( Gtk::Menu_Helpers::MenuElem("_Add",sigc::mem_fun(*this, &DocView::add) ) );
        //menulist.push_back( Gtk::Menu_Helpers::MenuElem("Add Folder",sigc::mem_fun(*this, &DocView::add_folder) ) );
        menulist.push_back( Gtk::Menu_Helpers::MenuElem("_Open",sigc::mem_fun(*this, &DocView::open_doc) ) );
        menuPopup.append(attachMenu);

        menuPopup.append(editdocMenu);
        //menulist.push_back( Gtk::Menu_Helpers::MenuElem("_Edit",sigc::mem_fun(*this, &DocView::edit_doc) ) );
        //menulist.push_back( Gtk::Menu_Helpers::MenuElem("_Remove", sigc::mem_fun(*this, &DocView::remove_doc) ) );
        //menulist.push_back( Gtk::Menu_Helpers::MenuElem("Remove All",sigc::mem_fun(*this, &DocView::remove_all_doc) ) );
        //添加菜单分隔线
        menulist.push_back( Gtk::Menu_Helpers::SeparatorElem() );
        menuPopup.append(addreadingMenu);
        menulist.push_back( Gtk::Menu_Helpers::MenuElem("Add Tags", sigc::mem_fun(*this, &DocView::addtags) ) );
        menulist.push_back( Gtk::Menu_Helpers::MenuElem("Finish Reading", sigc::mem_fun(*this, &DocView::finish_reading) ) );


        //the remove reading popup menu
        removereadingMenu.set_visible(false);

        //the remove writing popup menu
        removewritingMenu.set_visible(false);
        removewritingMenu.set_sensitive(false);

        removetagMenu.set_sensitive(false);

        menulist.push_back( Gtk::Menu_Helpers::SeparatorElem() );
        menuPopup.append(removereadingMenu);
        menuPopup.append(removewritingMenu);
        menuPopup.append(removetagMenu);
        menulist.push_back( Gtk::Menu_Helpers::SeparatorElem() );

        addthumbMenu.set_sensitive(false);

        menuPopup.append(addthumbMenu);
        menulist.push_back( Gtk::Menu_Helpers::SeparatorElem() );
        menulist.push_back( Gtk::Menu_Helpers::MenuElem("Attribute", sigc::mem_fun(*this, &DocView::showattribute) ) );

    }
    menuPopup.accelerate(*this);
    menuPopup.show_all();
}

DocView::~DocView()
{
}
void DocView::set_documents(sdms::documents* doc)
{
    mydoc=doc;
}
void DocView::set_tagview(TagView* t)
{
    tagview=t;
}
void DocView::set_writingview(WritingView* t)
{
    writingview=t;
}
void DocView::set_readingview(ReadingView* t)
{
    readingview=t;
}
void DocView::set_statusbar(Gtk::Statusbar* s)
{
    status=s;
}
void DocView::set_publisherview(PublisherView* t)
{
    publisherview=t;
}
//返回文件的所略图
//可以直接获取的图片类型直接获取
//否则获取类型图片
/*
Glib::RefPtr<Gdk::Pixbuf>  DocView::get_pixbuf(Gtk::TreeModel::Row& row,const std::string fn)
{
    //std::string filename=uri.substr(7);
    Glib::RefPtr<Gdk::Pixbuf> thumbnail;
    Glib::RefPtr<Gnome::Vfs::Uri> uri = Gnome::Vfs::Uri::create (fn);
    if (!fn.empty () && uri->uri_exists())
    {
        Glib::RefPtr<Gnome::Vfs::FileInfo> fileinfo = uri->get_file_info ();
        time_t mtime = fileinfo->get_modification_time ();
        Glib::RefPtr<Gnome::UI::ThumbnailFactory > thf=Gnome::UI::ThumbnailFactory::create(Gnome::UI::THUMBNAIL_SIZE_NORMAL);
        Glib::ustring thumbfile = thf->lookup (fn, mtime);
        //fileinfo->get_mime_type()返回空，是什么原因？
        //std::cout<<fileinfo->get_mime_type()<<std::endl;
        //std::cout<<fileinfo->get_name()<<std::endl;
        if (thumbfile.empty())
        {
            Glib::RefPtr<Gtk::IconTheme> theme = Gtk::IconTheme::get_default();
            //自定义的thumbnails文件，优先级最高
            std::string cachethumb=Glib::get_home_dir()+"/.thumbnails/normal/"+Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_MD5,fn)+".png";
            std::cout<<cachethumb<<std::endl;
            if (Glib::file_test(cachethumb,Glib::FILE_TEST_EXISTS)) return Gdk::Pixbuf::create_from_file (cachethumb);
            //std::cout<<cachethumb<<std::endl;

            //先行判断已知的无法获取thumbnail的文件类型
            if (theme)
            {
                std::string iconname=fn.substr(fn.find_last_of(".")+1);
                //笨拙的办法，因为不知道如何获取一个文件类型对应的ICON名称
                if (iconname=="chm") iconname="gnome-mime-application-x-chm";
                if (iconname=="odt" || iconname=="doc") iconname="x-office-document";
                if (iconname=="ppt" || iconname=="odp") iconname="x-office-presentation";
                if (theme->has_icon(iconname))
                {
                    return theme->load_icon(iconname, 48, Gtk::ICON_LOOKUP_FORCE_SVG|Gtk::ICON_LOOKUP_USE_BUILTIN );
                }
            }
            std::cerr << "Couldn't find thumbnail: " << fn << "'\n";
            if (thf->has_valid_failed_thumbnail (fn, mtime))
            {
                std::cerr << "Has valid failed thumbnail: " << fn << std::endl;
            }
            else
            {
                std::cerr << "Generate thumbnail: " << fn << std::endl;
                if (thf->can_thumbnail(fn,"application/pdf",mtime))
                {
                    //std::cout<<"can thumbnail."<<std::endl;
                    thumbnail = Gdk::Pixbuf::create_from_file ("images/image-loading.png");
                    sigc::connection toconn=Glib::signal_timeout().connect(sigc::bind(sigc::mem_fun(*this,&DocView::get_thumb),row,fn),300,Glib::PRIORITY_HIGH_IDLE);
                    return thumbnail;
                }
                //留待空闲时间生成图像？
                thumbnail = thf->generate_thumbnail (fn, "application/pdf");
                if (thumbnail)
                {
                    thf->save_thumbnail (thumbnail, fn, mtime);
                }
                else
                {
                    std::cerr << "Failed to generate thumbnail: " << fn << "'\n";
                    thf->create_failed_thumbnail (fn, mtime);
                }
            }
        }
        else
        {
            thumbnail = Gdk::Pixbuf::create_from_file (thumbfile);
        }
    }
    //thumbnail=th->generate_thumbnail(uri,"application/pdf");
    if (thumbnail)		return thumbnail;
    if (!uri->uri_exists())//文件不存在
    {
        std::cout<<fn<<std::endl;
        return 	Gdk::Pixbuf::create_from_file("images/not_exist.svg");
    }
    //std::cerr<<"get_pixbuf"<<std::endl;
    //suffix=utils::getfilesuffix(fn);
    //std::cout<<fn.substr(fn.find_last_of(".")+1)<<std::endl;

    //std::string filename="images/"+fn.substr(fn.find_last_of(".")+1)+".svg";
    return  Gdk::Pixbuf::create_from_file("images/unknown.svg");
}
*/

//use gtk to get the thumbnail
//could not generate new thumbnail
Glib::RefPtr<Gdk::Pixbuf>  DocView::get_pixbuf(const sdms::document& t)
{
    std::string uri=t.uri;
    if (t.uri.find_first_of("/")==0)
    {
        //Local disk file
        uri="file://"+t.uri;
        //自定义的thumbnails文件，优先级最高
        //replace utils::md5 with Glib::Checksum
        std::string cachethumb=Glib::get_home_dir()+"/.thumbnails/normal/"+Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_MD5,uri)+".png";
        if (Glib::file_test(cachethumb,Glib::FILE_TEST_EXISTS)) return Gdk::Pixbuf::create_from_file (cachethumb);
        //文件不存在
        if (!Glib::file_test(t.uri,Glib::FILE_TEST_EXISTS))
            return 	Gdk::Pixbuf::create_from_file("images/not_exist.svg");
    }
    std::string mime=utils::replace(t.mime,'/','-');
    if (!t.mime.empty() and t.mime!="NULL")
    {
        Glib::RefPtr<Gtk::IconTheme> theme = Gtk::IconTheme::get_default();
        if (theme->has_icon(mime))
            return theme->load_icon(mime, 48, Gtk::ICON_LOOKUP_FORCE_SVG|Gtk::ICON_LOOKUP_USE_BUILTIN );
        //else
        //return theme->load_icon("document", 48, Gtk::ICON_LOOKUP_FORCE_SVG|Gtk::ICON_LOOKUP_USE_BUILTIN );
    }
    return  Gdk::Pixbuf::create_from_file("images/unknown.svg");
}
/*
bool DocView::get_thumb(Gtk::TreeModel::Row& row,const std::string fn)
{
    Glib::RefPtr<Gnome::UI::ThumbnailFactory > thf=Gnome::UI::ThumbnailFactory::create(Gnome::UI::THUMBNAIL_SIZE_NORMAL);
    Glib::RefPtr<Gdk::Pixbuf> thumbnail = thf->generate_thumbnail (fn, "application/pdf");
    if (!thumbnail) return false;
    row[columns.pixbuf]=thumbnail;
    std::string cachethumb=Glib::get_home_dir()+"/.thumbnails/normal/"+Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_MD5,fn)+".png";
    thumbnail->save(cachethumb,"png");
    return false;
}
*/
void DocView::_update(std::vector<sdms::document>& t)
{
    refListModel->clear();
    Gtk::TreePath path;
    Gtk::TreeModel::iterator first;
    for(int i=0; i<t.size(); i++)
    {
        Gtk::TreeModel::iterator iter=refListModel->append();
        Gtk::TreeModel::Row row = *iter;
        if (i==0) path=refListModel->get_path(iter);
        row[columns.id] = t[i].id;
        row[columns.name] =  t[i].name;
        row[columns.click] =  t[i].click;
        row[columns.uri]=t[i].uri;
        row[columns.pixbuf]=get_pixbuf(t[i]);
        //sigc::slot<bool> gen_pix_slot=sigc::bind(sigc::mem_fun(*this,&DocView::get_thumb),row,t[i].uri);
        //sigc::connection toconn=Glib::signal_timeout().connect(gen_pix_slot,300*i,Glib::PRIORITY_HIGH_IDLE);
        //refListModel->row_changed(path,iter);
    }
    Glib::ustring m=" There are ";
    m+=utils::toString(t.size());
    m+=" items in current selection.";
    status->push(m,1);
    //scroll_to_path(path,false,gfloat(0.0),gfloat(0.0));
    //refListModel->set_sort_column(columns.name,Gtk::SORT_ASCENDING);
}
void DocView::update()
{
    if (!mydoc) return;
    std::vector<sdms::document> t=mydoc->getdocument();
    _update(t);
}
//更新基于过滤器的文档集合
void DocView::update(const sdms::Filter* f)
{
    std::cout<<f->tostring()<<std::endl;
    std::vector<sdms::document> t=mydoc->getdocument(f);
    _update(t);
}
void DocView::viewbook()
{
    if (!mydoc) return;
    std::vector<sdms::document> t=mydoc->getbook();
    _update(t);
}
void DocView::viewarticle()
{
    if (!mydoc) return;
    std::vector<sdms::document> t=mydoc->getarticle();
    _update(t);
}
void DocView::viewnopdfdocument()
{
    if (!mydoc) return;
    std::vector<sdms::document> t=mydoc->getnopdfdocument ();
    _update(t);
}
bool DocView::on_button_release_event(GdkEventButton* event)
{
    bool return_value = IconView::on_button_release_event(event);
    Gtk::TreeModel::Path path;
    if ((event->type == GDK_BUTTON_RELEASE) && (event->button == 1) )
    {
        //old_selected = get_selected_items();
        get_item_at_pos(int(event->x),int(event->y),path);
        if (mouse_x==int(event->x) && mouse_y==int(event->y) && path.get_depth() && !(event->state & GDK_SHIFT_MASK) && !(event->state & GDK_CONTROL_MASK) )
        {
            unselect_all();
            select_path(path);
        }
        old_selected=get_selected_items();
    }
    return return_value;
}
//处理弹出菜单
bool DocView::on_button_press_event(GdkEventButton* event)
{
    //Call base class, to allow normal handling,
    //such as allowing the row to be selected by the right-click:
    bool return_value = IconView::on_button_press_event(event);

    //Then do our custom stuff:
    Gtk::TreeModel::Path path;
    std::list<Gtk::TreeModel::Path> selected;
    if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1) )
    {
        //判断鼠标压下时，已经有被选中要素，有可能是要进行DND操作
        mouse_x=int(event->x);
        mouse_y=int(event->y);
        selected = get_selected_items();
        get_item_at_pos(int(event->x),int(event->y),path);
        if (path.get_depth() && path_is_selected(path) && old_selected.size())
        {
            //restore the old_selected
            for(std::list<Gtk::TreeModel::Path>::iterator i=old_selected.begin(); i!=old_selected.end(); i++)
            {
                select_path(*i);
            }

        }
        selected = get_selected_items();
        if(!selected.empty())
        {
            //begin drag
            std::cout<<selected.size()<<std::endl;
        }

        return return_value;
    }
    else if( (event->type == GDK_BUTTON_PRESS) && (event->button == 3) )
    {
        //首先判断是否有已经执黑的items
        selected = get_selected_items();
        mouse_x=int(event->x);
        mouse_y=int(event->y);
        Gtk::CellRenderer *cell(0);
        //滚屏后会产生奇怪的紊乱
        //get_dest_item_at_pos (int(event->x), int(event->y), path);
        get_item_at_pos(int(event->x),int(event->y),path,cell);
        if (path.get_depth())//path不为空
        {
            Gtk::TreeModel::iterator iter = refListModel->get_iter(path);
            //std::cout<<(*iter)[columns.name]<<std::endl;
            if (iter) //然后判断当前位置是否有有效的item
            {
                //右键所点击的位置没有执黑的要素
                if (selected.empty() || (!path_is_selected(path)))
                {
                    unselect_all();
                    select_path(path);
                    selected = get_selected_items();
                }
            }
        }
        if (selected.size()==1) //只有一个要素时才能编辑
        {
            editdocMenu.set_sensitive(true);
            editdocMenu.set_visible(true);
            addthumbMenu.set_sensitive(true);
            addthumbMenu.set_visible(true);
            editconn.disconnect();
            editconn=editdocMenu.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &DocView::edit_doc),path,cell));
            //TODO: echo the attachment menu if there are 2 attachments or more.
            sdms::document d;
            Gtk::TreeModel::iterator iter = refListModel->get_iter(path);
            d.id=(*iter)[columns.id];
            Glib::ustring u=(*iter)[columns.uri];
            d.uri=u;
            std::vector<sdms::attachment> va=mydoc->getattachment(d);
            if (va.size()>1)
            {
                Gtk::Menu* subMenu= manage( new Gtk::Menu() );
                for(int i=0; i<va.size(); i++)
                {
                    if (va[i].uri!=d.uri) subMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(va[i].uri, sigc::bind(sigc::mem_fun(*this, &DocView::open_attachment),va[i].uri) ) );
                }
                attachMenu.set_submenu(*subMenu);
                attachMenu.set_visible(true);
                attachMenu.set_sensitive(true);
            }
            else
            {
                attachMenu.set_visible(false);
                attachMenu.set_sensitive(false);
            }
            //TODO: echo the note menu if there are notes with this item.
        }
        else
        {
            editconn.disconnect();
            editdocMenu.set_sensitive(false);
            editdocMenu.set_visible(false);
            addthumbMenu.set_visible(false);
            addthumbMenu.set_sensitive(false);
            attachMenu.set_visible(false);
            attachMenu.set_sensitive(false);
        }
        if(!selected.empty())
        {
            std::vector<unsigned int> docid;
            for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
            {
                Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
                Gtk::TreeModel::Row row = *iter;
                docid.push_back(row[columns.id]);
            }
            //获取docid对应的公共属性，包括分类、theme、tag等
            //extra popup menu
            //to determine if echo the remove writing menu
            std::vector<sdms::writing> w=mydoc->getwriting(docid);
            Gtk::Menu* writingMenu= manage( new Gtk::Menu() ); //必须使用指针形式
            for(int i=0; i<w.size(); i++)
            {
                writingMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(w[i].name, sigc::bind(sigc::mem_fun(*this, &DocView::remove_writing),w[i].id) ) );
            }
            if (w.size())
            {
                writingMenu->set_sensitive(true);
                removewritingMenu.set_submenu(*writingMenu);
                removewritingMenu.set_visible(true);
                removewritingMenu.set_sensitive(true);
            }
            else
            {
                removewritingMenu.set_visible(false);
                removewritingMenu.set_sensitive(false);
            }
            //to determine if echo the remove reading menu
            if (mydoc->inreading(docid))
            {
                removereadingMenu.set_visible(true);
                removereadingMenu.set_sensitive(true);
                addreadingMenu.set_visible(false);
                addreadingMenu.set_sensitive(false);

            }
            else
            {
                removereadingMenu.set_visible(false);
                removereadingMenu.set_sensitive(false);
                addreadingMenu.set_visible(true);
                addreadingMenu.set_sensitive(true);

            }
            //to determine if echo the remove tag menu
            std::vector<sdms::tag> tags=mydoc->gettag(docid);
            Gtk::Menu* tMenu= manage( new Gtk::Menu() );
            for(int i=0; i<tags.size(); i++)
            {
                tMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(tags[i].name, sigc::bind(sigc::mem_fun(*this, &DocView::remove_tag),tags[i].id) ) );
            }
            if (tags.size())
            {
                removetagMenu.set_sensitive(true);
                removetagMenu.set_visible(true);
                removetagMenu.set_submenu(*tMenu);
            }
            else
            {
                removetagMenu.set_visible(false);
                removetagMenu.set_sensitive(false);
            }
        }
        menuPopup.popup(event->button, event->time);
    }
    return return_value;
}

//指定缩略图
void DocView::add_thumb()
{
    //首先打开文件对话框，让用户进行选择
    //选择后生成对应的文件，文件名称要进行MD5
    //md5("file:///path/to/filename");
    Gtk::FileChooserDialog dialog("Please choose a file",Gtk::FILE_CHOOSER_ACTION_OPEN);

    //Add response buttons the the dialog:
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
    Gtk::FileFilter filter;
    filter.set_name("Images");
    filter.add_mime_type("image/jpeg");
    filter.add_mime_type("image/gif");
    filter.add_mime_type("image/png");
    filter.add_mime_type("image/svg+xml");
    dialog.add_filter(filter);
    int result = dialog.run();
    if (result==Gtk::RESPONSE_OK)
    {
        Glib::RefPtr<Gdk::Pixbuf> pix=Gdk::Pixbuf::create_from_file(dialog.get_filename(),128,96);
        std::list<Gtk::TreeModel::Path> selected = get_selected_items();
        //if (selected.size()!=1) std::cerr<<"error, document number does not equal 1."<<std::endl;
        std::list<Gtk::TreeModel::Path>::iterator iter =selected.begin();
        Gtk::TreeModel::iterator it=refListModel->get_iter(*iter);
        Gtk::TreeModel::Row row=*it;
        row[columns.pixbuf]=pix;
        Glib::ustring uri=row[columns.uri];
        std::string cachethumb=Glib::get_home_dir()+"/.thumbnails/normal/"+Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_MD5,uri)+".png";
        pix->save(cachethumb,"png");
    }
}
//插入文档
void DocView::add()
{
    Gtk::FileChooserDialog dialog("Please choose a file",Gtk::FILE_CHOOSER_ACTION_OPEN);

    //Add response buttons the the dialog:
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
    //设置支持多选
    dialog.set_select_multiple(true);
    //Add filters, so that only certain file types can be selected:

    Gtk::FileFilter filter_cpp;
    filter_cpp.set_name("Document files");
    filter_cpp.add_mime_type("application/pdf");
    filter_cpp.add_mime_type("application/x-chm");
    dialog.add_filter(filter_cpp);

    Gtk::FileFilter filter_text;
    filter_text.set_name("Text files");
    filter_text.add_mime_type("text/plain");
    dialog.add_filter(filter_text);

    Gtk::FileFilter filter_any;
    filter_any.set_name("Any files");
    filter_any.add_pattern("*");
    dialog.add_filter(filter_any);

    //Show the dialog and wait for a user response:
    int result = dialog.run();
    //处理文件
    if (result==Gtk::RESPONSE_OK)
    {
        //std::vector<std::string> filenames =dialog.get_filenames();
        std::vector<std::string> filenames =dialog.get_filenames();//uris();
        for(int i=0; i<filenames.size(); i++)
        {
            //Notice that this is a std::string, not a Glib::ustring.
            //若采用uri，则中文就会进行编码，在调用本地文件时还需进行反编码。
            //std::string filename = dialog.get_filename();
            std::cout << "File selected: " <<  filenames[i] << std::endl;
            std::cout<<Glib::path_get_basename(filenames[i])<<std::endl;
            sdms::document d;
            d.uri=filenames[i];
            d.name=Glib::path_get_basename(filenames[i]);
            mydoc->add(&d);
            Gtk::TreeModel::Row row = *(refListModel->append());
            row[columns.name] = d.name;
            row[columns.uri]=d.uri;
            row[columns.id]=d.id;
            row[columns.click]=0;
            row[columns.pixbuf]=get_pixbuf(d);
        }
    }
}

void DocView::add_folder()
{
    Gtk::FileChooserDialog dialog("Please choose a directory",Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
    dialog.set_select_multiple(true);
    int result = dialog.run();
    if (result==Gtk::RESPONSE_OK)
    {
        std::vector<std::string> filenames =dialog.get_filenames();//uris();
        for(int i=0; i<filenames.size(); i++)
        {
            std::cout << "File selected: " <<  filenames[i] << std::endl;
            onAddFolder(filenames[i]);
        }
    }
}
void DocView::onAddFolder (const std::string& filename)
{
    if (Glib::file_test(filename,Glib::FILE_TEST_IS_DIR))
    {
        Glib::Dir dir(filename);
        std::list<std::string> entries (dir.begin(), dir.end());
        for(std::list<std::string>::iterator it=entries.begin(); it!=entries.end(); it++)
        {
            onAddFolder(filename+"/"+(*it));
        }
    }
    else     //file
    {
        if (!(Glib::str_has_suffix(filename,"pdf") || Glib::str_has_suffix(filename,"chm") || Glib::str_has_suffix(filename,"doc"))) return;
        std::cout<<"(in add_folder)"<<filename<<std::endl;
        sdms::document d;
        d.uri=filename;
        d.name=Glib::path_get_basename(filename);
        if (mydoc->add(&d))
        {
            Gtk::TreeModel::Row row = *(refListModel->append());
            row[columns.name] = d.name;
            row[columns.uri]=d.uri;
            row[columns.id]=d.id;
            row[columns.click]=0;
            row[columns.pixbuf]=get_pixbuf(d);
        }
    }
}

//调用外部程序，打开对应的文档
void DocView::open_doc()
{
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
        {
            Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
            select_doc(refListModel->get_path(iter));
        }
    }
}

//保存当前编辑的document
void DocView::save_doc(const Glib::ustring& path_string, const Glib::ustring& new_text)
{
    std::cout << "Test save_doc function." << std::endl;
    Gtk::TreePath path(path_string);
    if (editstatus)
    {
        //Get the row from the path:
        Gtk::TreeModel::iterator iter = refListModel->get_iter(path);
        if(iter)
        {
            Gtk::TreeModel::Row row = *iter;

            sdms::document doc;
            doc.name=new_text;
            doc.id=row[columns.id];
            if (doc.id)
            {
                //update doc table
                if (mydoc->update(&doc)) row[columns.name] = new_text;
            }
            else
            {
                //new doc
                if(mydoc && mydoc->add(&doc))
                {
                    row[columns.name] = new_text;
                    row[columns.id]=doc.id;
                }
                else
                    refListModel->erase(iter);
            }
            //cellrenderer->property_editable()=false;
            editstatus=false;
        }
    }
}

//iconview里如何设置属性编辑？
void DocView::edit_doc(Gtk::TreeModel::Path& path,Gtk::CellRenderer*& cell)
{
    Gtk::CellRendererText* crt=static_cast<Gtk::CellRendererText*>(cell);
    crt->property_editable()=true;
    startconn=crt->signal_editing_started().connect(sigc::mem_fun(this,&DocView::edit_started));
    set_cursor(path,*cell,true);
    crt->property_editable()=false;

    /* use dialog to edit the name.
    InputtextDialog dialog;
    dialog.set_text((*it)[columns.name]);
    int result=dialog.run();
    Glib::ustring name=dialog.get_text();
    if (result && !name.empty())
    {
    	sdms::document d;
    	d.id=(*it)[columns.id];
    	d.name=name;
    	if (mydoc->update(&d)) (*it)[columns.name]=name;
    }*/
}
void DocView::edit_started(Gtk::CellEditable* editable, const Glib::ustring& path)
{
    startconn.disconnect();
    if (editable)
        doneconn = editable->signal_editing_done().connect(sigc::bind(sigc::mem_fun(this, &DocView::edit_done), editable));
}
void DocView::edit_done(Gtk::CellEditable* editable)
{
    Gtk::Entry* entry = static_cast<Gtk::Entry*>(editable);
    if (entry)
    {
        std::list<Gtk::TreeModel::Path> selected = get_selected_items();
        if (selected.size()!=1) std::cerr<<"error, document number does not equal 1."<<std::endl;
        std::list<Gtk::TreeModel::Path>::iterator iter =selected.begin();
        Gtk::TreeModel::iterator it=refListModel->get_iter(*iter);
        Gtk::TreeModel::Row row = *it;
        if (row)
        {
            std::string data("");
            row.get_value(get_text_column(), data);
            if (data != entry->get_text())
            {
                row.set_value(get_text_column(), entry->get_text());
                if (!entry->get_text().empty())
                {
                    sdms::document d;
                    d.id=row[columns.id];
                    d.name=entry->get_text();
                    mydoc->update(&d);
                }
            }

        }
    }
    doneconn.disconnect();
}
//删除一个或多个被选择的文档，弹出对话框请用户确认
void DocView::remove_doc()
{
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        Gtk::MessageDialog dialog("Are you sure to delete?", false, Gtk::MESSAGE_QUESTION,Gtk::BUTTONS_OK_CANCEL,true);
        int result=dialog.run();
        if (result==Gtk::RESPONSE_OK )
        {
            for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
            {
                //Gtk::TreeModel::Path& path = i;
                Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
                Gtk::TreeModel::Row row = *iter;
                //std::string uri=row[columns.uri];//需要进行类型转换，奇怪
                //std::cout<<uri<<std::endl;
                sdms::document doc;
                doc.id=row[columns.id];
                //doc.name=(*iter)[columns.name];
                if (mydoc->del(&doc))	refListModel->erase(iter);
            }
        }
        if (tagview) tagview->update();
        if (writingview) writingview->update();
        if (publisherview) publisherview->update();
    }
}

//删除所有主题
void DocView::remove_all_doc()
{
    Gtk::MessageDialog dialog("Are you sure to delete all docs?", false, Gtk::MESSAGE_QUESTION,Gtk::BUTTONS_OK_CANCEL,true);
    int result=dialog.run();
    if (result==Gtk::RESPONSE_OK )
    {
        sdms::document doc;
        //doc.id=0;
        mydoc->del(&doc);
        refListModel->clear();
    }
    if (tagview) tagview->update();
    if (writingview) writingview->update();
    if (publisherview) publisherview->update();
}
void DocView::datarender(Gtk::CellRenderer* /* renderer */, const Gtk::TreeModel::iterator& iter)
{
    //Get the value from the model and show it appropriately in the view:
    if(iter)
    {
        Gtk::TreeModel::Row row = *iter;
        //std::string model_value = row[columns.name];
        //cellrenderer.property_text() = row[columns.name];
    }
}

void DocView::open_attachment(const std::string& uri)
{
    std::string fn=uri;
    if (fn.find_first_of("/")==0)
    {
        fn="file://"+fn;
        //Gnome::Vfs::url_show (fn);
        gtk_show_uri(NULL,fn.c_str(),GDK_CURRENT_TIME,NULL);
    }
    else if (fn.find_first_of("http://")==0)
    {
        //use firefox open the url.
        //Gnome::Vfs::url_show (fn);
        gtk_show_uri(NULL,fn.c_str(),GDK_CURRENT_TIME,NULL);
    }
    else if (fn.find_first_of("zotero://")==0)
    {
        //use firefox open the url.
        Glib::ArrayHandle<std::string> args = Glib::shell_parse_argv("firefox "+fn);
        Glib::spawn_async("./", args, Glib::SPAWN_SEARCH_PATH | Glib::SPAWN_STDOUT_TO_DEV_NULL | Glib::SPAWN_STDERR_TO_DEV_NULL);
    }
    else
        std::cerr<<"no file uri in document uri: "<<fn<<std::endl;

}
//处理专题的选择，必须在非编辑状态下运行
//调用主界面的窗口，增加过滤器
void DocView::select_doc(const Gtk::TreeModel::Path& path)
{
    Gtk::TreeModel::iterator iter = refListModel->get_iter(path);
    Gtk::TreeModel::Row row = *iter;
    Glib::ustring fn=row[columns.uri];
    std::cout<<fn<<std::endl;
    open_attachment(fn);
    /* GTK WAY
    std::string filename="evince ";
    filename+=row[columns.uri];
    std::string wdir="./";
    	try {
    		Glib::ArrayHandle<std::string> args = Glib::shell_parse_argv(filename);
    		Glib::spawn_async(wdir, args, Glib::SPAWN_SEARCH_PATH | Glib::SPAWN_STDOUT_TO_DEV_NULL | Glib::SPAWN_STDERR_TO_DEV_NULL);
    	std::cout<<"args:"<<std::endl;
    	} catch ( Glib::SpawnError &e ) {
    		std::cout<<Glib::locale_from_utf8(e.what())<<std::endl;
    	}
    */
}

//Todo:显示文档的属性
void DocView::showattribute()
{
    std::cout << "Test attribute function." << std::endl;
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    std::cout<<selected.size()<<std::endl;
}
//Todo:添加或修改文档的标签(tag)
//显示添加文档标签的窗口就足够了
//剩下的工作交给提交按钮进行处理
void DocView::addtags()
{
    std::cout << "Test addtags function." << std::endl;
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        //首先显示addtags窗口，用户输入TAGS后再点击添加或应用按钮
        //然后再进行TAGS和对应文档的保存工作
        InputtextDialog dialog;
        dialog.set_title("Add new tags, seperate with comma");
        int result=dialog.run();
        std::string newtag=dialog.get_text();
        if (result && !newtag.empty())
        {
            std::vector<std::string> tags=utils::explode(newtag,",");
            for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
            {
                //Gtk::TreeModel::Path& path = i;
                Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
                Gtk::TreeModel::Row row = *iter;
                //std::string uri=row[columns.uri];//需要进行类型转换，奇怪
                //std::cout<<uri<<std::endl;
                sdms::document doc;
                doc.id=row[columns.id];
                mydoc->update(tags,&doc);
                //doc.name=(*iter)[columns.name];
                //if (mydoc->del(&doc))	refListModel->erase(iter);
            }
        }
        if (tagview) tagview->update();
    }
}
void DocView::drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,   Gtk::SelectionData& selection_data, guint, guint)
{
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    std::string id;
    if(!selected.empty())
    {
        //有执黑的要素any selected items
        for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
        {
            Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
            Gtk::TreeModel::Row row = *iter;
            if (i!=selected.begin()) id+=",";
            id+=sqlite::toString(row[columns.id]);
        }
    }
    selection_data.set(selection_data.get_target(), 8 /* 8 bits format */,
                       (const guchar*)id.c_str(),id.size());
}

void DocView::remove_writing(unsigned int id)
{
    sdms::writing t;
    t.id=id;
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
        {
            //Gtk::TreeModel::Path& path = i;
            Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
            Gtk::TreeModel::Row row = *iter;
            sdms::document d;
            d.id=row[columns.id];
            mydoc->del(&t,&d);
        }
        unselect_all();
        if (writingview) writingview->update();
    }
}
void DocView::add_reading()
{
    sdms::reading t;
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        //popup the calendar dialog
        CalendarDialog cdialog("Please choose the schedual date");
        int res=cdialog.run();
        if (!res) return;
        guint year,month,day;
        cdialog.get_date(year,month,day);
        month++;
        t.plan=utils::toString(year)+"-";
        if (month<10) t.plan+="0";
        t.plan+=utils::toString(month)+"-";
        if (day<10) t.plan+="0";
        t.plan+=utils::toString(day);
        for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
        {
            //Gtk::TreeModel::Path& path = i;
            Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
            Gtk::TreeModel::Row row = *iter;
            t.id=row[columns.id];
            mydoc->add(&t);
        }
        unselect_all();
        if (readingview) readingview->update();
    }
}
void DocView::finish_reading()
{
    sdms::reading t;
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        //popup the calendar dialog
        CalendarDialog cdialog("Please choose the finish date");
        int res=cdialog.run();
        if (!res) return;
        guint year,month,day;
        cdialog.get_date(year,month,day);
        month++;
        t.finish=utils::toString(year)+"-";
        if (month<10) t.finish+="0";
        t.finish+=utils::toString(month)+"-";
        if (day<10) t.finish+="0";
        t.finish+=utils::toString(day);
        for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
        {
            //Gtk::TreeModel::Path& path = i;
            Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
            Gtk::TreeModel::Row row = *iter;
            t.id=row[columns.id];
            mydoc->add(&t);
        }
        unselect_all();
        if (readingview) readingview->update();
    }
}
void DocView::remove_reading()
{
    sdms::reading t;
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
        {
            //Gtk::TreeModel::Path& path = i;
            Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
            Gtk::TreeModel::Row row = *iter;
            sdms::document d;
            d.id=row[columns.id];
            mydoc->del(t,d);
        }
        unselect_all();
        //if (readingview) readingview->update();
    }
}
void DocView::remove_tag(unsigned int id)
{
    sdms::tag t;
    t.id=id;
    std::list<Gtk::TreeModel::Path> selected = get_selected_items();
    if(!selected.empty())
    {
        for(std::list<Gtk::TreeModel::Path>::iterator i=selected.begin(); i!=selected.end(); i++)
        {
            //Gtk::TreeModel::Path& path = i;
            Gtk::TreeModel::iterator iter = refListModel->get_iter(*i);
            Gtk::TreeModel::Row row = *iter;
            sdms::document d;
            d.id=row[columns.id];
            mydoc->del(&t,&d);
        }
        if (tagview) tagview->update();
    }
}
void DocView::onSelectionChanged()
{
    //cellrenderer->stop_editing();
    //cellrenderer->set_property("editable",false);
}
void DocView::onSaveEditing(const Glib::ustring& path_string, const Glib::ustring& new_text)
{
    Gtk::TreePath path(path_string);
    //Get the row from the path:
    Gtk::TreeModel::iterator iter = refListModel->get_iter(path);
    if(iter)
    {
        Gtk::TreeModel::Row row = *iter;

        sdms::document doc;
        doc.name=new_text;
        doc.id=row[columns.id];
        if (doc.id)
        {
            //update doc table
            if (mydoc->update(&doc)) row[columns.name] = new_text;
        }
        else
        {
            //new doc
            if(mydoc && mydoc->add(&doc))
            {
                row[columns.name] = new_text;
                row[columns.id]=doc.id;
            }
            else
                refListModel->erase(iter);
        }
    }
    //cellrenderer->stop_editing();
}
